﻿using System.Collections.Generic;

namespace Gamelight.Input
{
	public static class InputManager
	{
		private static Dictionary<Gamelight.Input.Key, bool> isKeyPressed = new Dictionary<Key, bool>();

		private static List<InputEvent> eventQueue = new List<InputEvent>();

		private static int lastMouseX = 0;
		private static int lastMouseY = 0;

		internal static InputEvent[] GetAndClearEvents()
		{
			InputEvent[] events = eventQueue.ToArray();
			eventQueue.Clear();
			return events;
		}

		public static int MouseCurrentX { get { return InputManager.lastMouseX; } }
		public static int MouseCurrentY { get { return InputManager.lastMouseY; } }

        public static bool IsKeyPressed(Gamelight.Input.Key key)
		{
			bool isPressed;
			if (isKeyPressed.TryGetValue(key, out isPressed))
			{
				return isPressed;
			}
			return false;
		}

		internal static void MouseEnter(int x, int y)
		{
			InputManager.lastMouseX = x;
			InputManager.lastMouseY = y;
			eventQueue.Add(InputEvent.CreateMouseEnterEvent(x, y));
		}

		internal static void MouseLeave(int x, int y)
		{
			eventQueue.Add(InputEvent.CreateMouseLeaveEvent(x, y));
		}

		internal static void MouseDown(bool isLeft, int x, int y)
		{
			InputManager.lastMouseX = x;
			InputManager.lastMouseY = y;
			eventQueue.Add(InputEvent.CreateMouseDownEvent(isLeft ? MouseButton.Left : MouseButton.Right, x, y));
		}

		internal static void MouseUp(bool isLeft, int x, int y)
		{
			InputManager.lastMouseX = x;
			InputManager.lastMouseY = y;
			eventQueue.Add(InputEvent.CreateMouseUpEvent(isLeft ? MouseButton.Left : MouseButton.Right, x, y));
		}

		internal static void MouseMove(int x, int y)
		{
			InputManager.lastMouseX = x;
			InputManager.lastMouseY = y;
			eventQueue.Add(InputEvent.CreateMouseMoveEvent(x, y));
		}

        private static Key MapWindowsKeyToGamelightKey(System.Windows.Input.Key key, int platformKeyCode)
		{
			int winKeyCode = (int)key;

			// letters
			if (winKeyCode >= 30 && winKeyCode <= 55)
			{
				return (Key)(winKeyCode - 29);
			}

			// numbers
			else if (winKeyCode >= 20 && winKeyCode <= 29)
			{
				return (Key)(winKeyCode + 10);
			}

			// F1 through F12
			else if (winKeyCode >= 56 && winKeyCode <= 67)
			{
				return (Key)(winKeyCode - 15);
			}

			// Num pad numbers
			else if (winKeyCode >= 68 && winKeyCode <= 77)
			{
				return (Key)(winKeyCode - 8);
			}

			switch (key)
			{
				// arrows
				case System.Windows.Input.Key.Up:
					return Key.Up;
				case System.Windows.Input.Key.Down:
					return Key.Down;
				case System.Windows.Input.Key.Left:
					return Key.Left;
				case System.Windows.Input.Key.Right:
					return Key.Right;

				// other
				case System.Windows.Input.Key.Enter:
					return Key.Enter;
				case System.Windows.Input.Key.Space:
					return Key.Space;
				case System.Windows.Input.Key.Escape:
					return Key.Escape;
				case System.Windows.Input.Key.Tab:
					return Key.Tab;
				case System.Windows.Input.Key.Shift:
					return Key.Shift;
				case System.Windows.Input.Key.Ctrl:
					return Key.Control;
				case System.Windows.Input.Key.Back:
					return Key.Backspace;
				case System.Windows.Input.Key.Home:
					return Key.Home;
				case System.Windows.Input.Key.End:
					return Key.End;
				case System.Windows.Input.Key.Insert:
					return Key.Insert;
				case System.Windows.Input.Key.Delete:
					return Key.Delete;
				case System.Windows.Input.Key.PageUp:
					return Key.PageUp;
				case System.Windows.Input.Key.PageDown:
					return Key.PageDown;

				// not mapped yet
				default:
					return GetKeyFromPlatformKeyCode(platformKeyCode);
			}
		}

		private static Key GetKeyFromPlatformKeyCode(int keyCode)
		{
			if (System.Environment.OSVersion.Platform == System.PlatformID.MacOSX)
			{
				return GetKeyFromMacPlatformCode(keyCode);
			}

			if (System.Environment.OSVersion.Platform == System.PlatformID.Unix)
			{
				return GetKeyFromLinuxPlatformCode(keyCode);
			}

			return GetKeyFromWindowsPlatformCode(keyCode);
		}

		private static Key GetKeyFromMacPlatformCode(int keyCode)
		{
			// TODO: figure these out
			return Key.Unknown;
		}

		private static Key GetKeyFromLinuxPlatformCode(int keyCode)
		{
			// TODO: figure these out
			return Key.Unknown;
		}

		private static Key GetKeyFromWindowsPlatformCode(int keyCode)
		{
			switch (keyCode)
			{
				case 19: return Key.Break;
				case 44: return Key.PrintScreen;
				case 92: return Key.WindowsKey;
				case 93: return Key.InvokeContextMenu;
				case 144: return Key.NumLock;
				case 145: return Key.ScrollLock;
				case 173: return Key.KeyboardMuteButton;
				case 174: return Key.KeyboardVolumeDownButton;
				case 175: return Key.KeyboardVolumeUpButton;
				case 178: return Key.KeyboardMusicStopButton;
				case 179: return Key.KeyboardMusicPlayPauseButton;
				case 186: return Key.Semicolon;
				case 187: return Key.Equals;
				case 188: return Key.Comma;
				case 189: return Key.Hyphen;
				case 190: return Key.Period;
				case 191: return Key.Slash;
				case 192: return Key.Tilde;
				case 219: return Key.BracketOpen;
				case 220: return Key.Backslash;
				case 221: return Key.BracketClose;
				case 222: return Key.Apostrophe;

				default: return Key.Unknown;
			}
		}

		internal static Key KeyDown(System.Windows.Input.Key key, int platformCode)
		{
            Key gamelightKey = MapWindowsKeyToGamelightKey(key, platformCode);
			if (gamelightKey != Key.Unknown)
			{
				isKeyPressed[gamelightKey] = true;
				InputEvent e = InputEvent.CreateKeyDownEvent(gamelightKey);
				eventQueue.Add(e);
			}
			return gamelightKey;
		}

		internal static void KeyUp(System.Windows.Input.Key key, int platformCode)
		{
            Key gamelightKey = MapWindowsKeyToGamelightKey(key, platformCode);
			if (gamelightKey != Key.Unknown)
			{
				isKeyPressed[gamelightKey] = false;
				InputEvent e = InputEvent.CreateKeyUpEvent(gamelightKey);
				eventQueue.Add(e);
			}
		}
	}
}
